﻿using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;

namespace Notoric.View.Music.CWNotation.Controls
{
    /// <summary>
    /// Visualizes the interior of the music section.
    /// </summary>
    public partial class MusicSectionInterior : UserControl
    {
        #region Constructors

        /// <summary>
        /// Creates a new <see cref="MusicSectionInterior"/> instance.
        /// </summary>
        public MusicSectionInterior()
        {
            InitializeComponent();
        }

        #endregion

        #region Event Handlers

        /// <summary>
        /// Occurs when the data context (visualized section interior) has changed.
        /// </summary>
        /// <param name="sender">Object that has sent the event</param>
        /// <param name="e">Event data</param>
        private void UserControl_DataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
        {
            interior = (ViewModel.Elements.CWNotation.MusicSectionInterior)DataContext;

            if (interior != null)
                symbolInserter = interior.SymbolInserter;
        }

        /// <summary>
        /// Occurs when the user moves the mouse cursor over the section area.
        /// </summary>
        /// <param name="sender">Object where the event handler is attached</param>
        /// <param name="e">Event data</param>
        private void UserControl_MouseMove(object sender, MouseEventArgs e)
        {
            if (symbolInserter != null)
                symbolInserter.SetPosition(e.GetPosition(this));
        }

        /// <summary>
        /// Occurs when the user has drawn a rubber band in the area of the section interior.
        /// </summary>
        /// <param name="sender">Object where the event handler is attached</param>
        /// <param name="e">Event data</param>
        private void UserControl_RubberBandDrawn(object sender, RubberBandDrawnEventArgs e)
        {
            var selectionRect = new Rect(e.Left, e.Top, e.Width, e.Height);
            var hitTestParams = new GeometryHitTestParameters(new RectangleGeometry(selectionRect));
            interior.ClearSelection();
            MainCanvas.DrawRubberBand = true;

            VisualTreeHelper.HitTest(this, SelectionFilterCallback, SelectionResultCallback, hitTestParams);

            if (interior.Selection.Count > 0)
                MainCanvas.DrawRubberBand = false;

            e.Handled = true;
        }

        /// <summary>
        /// Occurs when the user has pressed the left mouse button in the area of the section interior.
        /// </summary>
        /// <param name="sender">Object where the event handler is attached</param>
        /// <param name="e">Event data</param>
        private void UserControl_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            interior.ClearSelection();
            interior.SelectedArc = null;
            interior.SelectedProgressMark = null;
            MainCanvas.DrawRubberBand = true;
            e.Handled = true;
        }

        #endregion

        #region Private Methods

        /// <summary>
        /// Filters the objects during the selection range hit-test.
        /// </summary>
        /// <param name="d">Dependency object that is currently being processed</param>
        /// <returns>The action to be taken on this visual tree node</returns>
        private HitTestFilterBehavior SelectionFilterCallback(DependencyObject d)
        {
            return HitTestFilterBehavior.Continue;
        }

        /// <summary>
        /// Adds core symbols in the current selection range to the selection.
        /// </summary>
        /// <param name="result">Current hit-test result</param>
        /// <returns>The action that will follow</returns>
        private HitTestResultBehavior SelectionResultCallback(HitTestResult result)
        {
            var dc = ((FrameworkElement)result.VisualHit).DataContext;
            if (dc is ViewModel.Elements.CWNotation.CoreSymbol)
                interior.AddToSelection(dc as ViewModel.Elements.CWNotation.CoreSymbol);
            else if (dc is ViewModel.Elements.CWNotation.Note)
                interior.AddToSelection(((ViewModel.Elements.CWNotation.Note)dc).FindOwner<ViewModel.Elements.CWNotation.Chord>());
            return HitTestResultBehavior.Continue;
        }

        #endregion

        #region Private Fields

        /// <summary>
        /// Holds the visualized music section interior.
        /// </summary>
        private ViewModel.Elements.CWNotation.MusicSectionInterior interior;
        /// <summary>
        /// Holds the symbol inserter.
        /// </summary>
        private ViewModel.Elements.CWNotation.CoreSymbolInserter symbolInserter;

        #endregion
    }
}
